package cbbx_sm.evaluation;

import java.util.ArrayList;
import java.util.List;

import org.junit.Test;

import cbbx_sm.decision_maker.search.DynamicProgrammingLookahead;
import cbbx_sm.endtoend.EndToEndTestUtils;
import cbbx_sm.parser.CameraData;
import cbbx_sm.probabilistic_model.ProbabilisticModel;
import cbbx_sm.utils.ExperimentManager;
import cbbx_sm.utils.LookaheadPredictorSerializator;

public class CompareAlternativeSchedulers {
	public enum Decision {mostlikelyAlways, mostlikelyWhenMotion, smartMostlikely, lookahead, rr, oracle, rrGOUP, up, lookaheadLocalProb, treeLookahead}

	@Test public void printLookaheadTableStatesSize() throws Exception {
		
		double utilityZoom = 1;
		double utilityUP = 0;
		double delta = 0.1;
		int numberOfTimeStampsLookAhead = 10;
		int numClusters = 4;
		ArrayList<String> cameraIds = new ArrayList<String>();
		cameraIds.add("cam8");
		cameraIds.add("cam9");
		cameraIds.add("cam10");
		cameraIds.add("cam11");
		cameraIds.add("cam12");
		cameraIds.add("cam13");
		cameraIds.add("cam14");
		cameraIds.add("cam15");
		cameraIds.add("cam16");
		cameraIds.add("cam17");
		cameraIds.add("cam18");
		
		cameraIds.add("cam19");
		cameraIds.add("cam20");
		cameraIds.add("cam21");
		cameraIds.add("cam22");
		cameraIds.add("cam23");
		cameraIds.add("cam24");
		cameraIds.add("cam25");
		cameraIds.add("cam26");
		cameraIds.add("cam27");
		cameraIds.add("cam28");
		cameraIds.add("cam29");
		
		// Load the probabilistic model or create it.
	    String camerasConcat = "";
		int i=0;
		for (String cam: cameraIds){
		  camerasConcat+=cam+(i<(cameraIds.size()-1)?"_":"");
		  i++;
		}
		String modelFileName = "model"+camerasConcat+"_"+"k="+numClusters+"_kmeans.ser";
		for (int clusters=4; clusters<5; clusters++){
		  utilityUP = 0;
		//for (delta = 0.15; delta > 0; delta-=0.05) {
		  delta = 0.05;
		  for (; utilityUP<=1; utilityUP+=0.1){
			for (String cam: cameraIds){
			  // Load model to figure out which index was each cluster when single camera model was created.
			  List<CameraData> singleCameraTrain = new ArrayList<CameraData>();
			  singleCameraTrain.add(cameraData.get(cam));
			  ProbabilisticModel singleCamModel =  new ProbabilisticModel(singleCameraTrain, camClusters.get(cam));
			
				DynamicProgrammingLookahead camTable =
						LookaheadPredictorSerializator.generateLookaheadTable(
							singleCamModel, utilityZoom, utilityUP, numberOfTimeStampsLookAhead, false, delta,
							10000, false);
			  boolean foundDiffBiggerEpsilon = false;
			  for (int j=0; j < camTable.getTable()[0].length; j++) {
				  if (camTable.getTable()[j].scoreCeiling - camTable.getTable()[j].scoreFloor > delta) {
					  foundDiffBiggerEpsilon = true;
					  break;
				  }
			  }
			  System.out.println("CameraLookuptable:" + cam + "\t" + camTable.getTable().length + "\t" + delta + "\t" + foundDiffBiggerEpsilon);
			 }
		//	}
		  }
		}
	}
	@Test public void compareAlternatives() throws NumberFormatException, Exception{
		//String testDay = "20090526-short";
		String testDay = ExperimentManager.testDay;
		//String testDay = "20090527";
		//DO NOT CHANGE
		String trainDay = ExperimentManager.trainDay;
		if (ExperimentManager.isViewEnabled || 
				ExperimentManager.useManualDataFormat) {
			trainDay = "20090528";
		}
		boolean runBaselineAlternatives = ExperimentManager.runBaselineAlternatives;
		boolean runMostLikelyAlternative = ExperimentManager.runMostLikelyAlternative;
		boolean runLookAheadAlternatives = ExperimentManager.runLookAheadAlternatives;
		boolean increaseBeta = ExperimentManager.increaseBeta;
		boolean largeNetwork = ExperimentManager.largeNetwork;
		boolean performExtraExperiments = ExperimentManager.performExtraExperiments;
		boolean performLookahead1 = ExperimentManager.performLookahead1;
		boolean performOracle = ExperimentManager.performOracle;
		boolean performSmartMostLikely = ExperimentManager.performSmartMostLikely;
		boolean performTreeLookahead = ExperimentManager.performTreeLookahead;
		boolean noCache = ExperimentManager.noCache;
		boolean discounting = ExperimentManager.discounting;

		double utilityZoom = ExperimentManager.utilityZoom;
		double utilityUP = ExperimentManager.utilityUP;
		double utilityUPStartValue = ExperimentManager.utilityUPStartValue;
		double utilityUPEndValue = ExperimentManager.utilityUPEndValue;

		double error = ExperimentManager.error;
		int numberOfTimeStampsLookAhead = ExperimentManager.numberOfTimeStampsLookAhead;
		int numberOfSecondsCorrelation = ExperimentManager.numberOfSecondsCorrelation;

		int stateSize = ExperimentManager.stateSize;
		
		boolean useAprioriProb = ExperimentManager.useAprioriProb;
		int timeInFuture = ExperimentManager.timeInFuture;
		
		// Cameras scheduled.
		ArrayList<String> cameraIds = getCameraIds(largeNetwork);
		
		for (int clusters=ExperimentManager.numberOfClustersStart; clusters<=ExperimentManager.numberOfClustersEnd; clusters+=1){
		  if (runMostLikelyAlternative) {
			  // Most likely always
			  performEvaluation(cameraIds, clusters, Decision.mostlikelyAlways,useAprioriProb, timeInFuture, utilityZoom, utilityUP, -1, discounting,
				       error, numberOfTimeStampsLookAhead, numberOfSecondsCorrelation, trainDay, testDay, noCache);
			  
		  }
		  if (runBaselineAlternatives){
			  // UP
			  performEvaluation(cameraIds, clusters, Decision.up, useAprioriProb, timeInFuture,utilityZoom, utilityUP, -1, discounting,
					  error, numberOfTimeStampsLookAhead, numberOfSecondsCorrelation, trainDay, testDay, noCache);	
			  
			  // RR
			  performEvaluation(cameraIds, clusters, Decision.rr, useAprioriProb, timeInFuture,utilityZoom, utilityUP, -1, discounting, 
					   error, numberOfTimeStampsLookAhead, numberOfSecondsCorrelation, trainDay, testDay, noCache);
					
			  // RR go up
			  performEvaluation(cameraIds, clusters, Decision.rrGOUP, useAprioriProb, timeInFuture,utilityZoom, utilityUP, -1, discounting,
					  error, numberOfTimeStampsLookAhead, numberOfSecondsCorrelation, trainDay, testDay, noCache);
	
			  // Most likely when motion
			  performEvaluation(cameraIds, clusters, Decision.mostlikelyWhenMotion, useAprioriProb, timeInFuture,utilityZoom, utilityUP, -1, discounting,
					  error, numberOfTimeStampsLookAhead, numberOfSecondsCorrelation, trainDay, testDay, noCache);			  
	      }
		  for (utilityUP = utilityUPStartValue; utilityUP <= utilityUPEndValue; utilityUP += 0.1) {
			  if (performOracle) {
				  // Oracle
				  performEvaluation(cameraIds, clusters, Decision.oracle, useAprioriProb, timeInFuture,utilityZoom, utilityUP, -1, discounting,
						  error, numberOfTimeStampsLookAhead, numberOfSecondsCorrelation, trainDay, testDay, noCache);  
			  }
			  if (performSmartMostLikely) {
				  performEvaluation(cameraIds, clusters, Decision.smartMostlikely, useAprioriProb, timeInFuture,utilityZoom, utilityUP, -1, discounting,
							error, numberOfTimeStampsLookAhead, numberOfSecondsCorrelation, trainDay, testDay, noCache);
			  }
			  if (performTreeLookahead) {
				  // NOTICE:  the tree lookahead technique is used to learn the initial grid lines, 
				  // It does so over the traning data (not the test data).
				  performEvaluation(cameraIds, clusters, Decision.treeLookahead, useAprioriProb, timeInFuture,utilityZoom, utilityUP, -1, discounting,
							error, numberOfTimeStampsLookAhead, numberOfSecondsCorrelation, trainDay, testDay, noCache);
			  }
			  if (runLookAheadAlternatives){
			    	// Lookahead = future
				  if (performLookahead1) {
					  performEvaluation(cameraIds, clusters, Decision.lookahead, useAprioriProb, timeInFuture,utilityZoom, utilityUP, stateSize, discounting,
								error, 1, numberOfSecondsCorrelation, trainDay, testDay, noCache);  
				  }
				  performEvaluation(cameraIds, clusters, Decision.lookahead, useAprioriProb, timeInFuture,utilityZoom, 
						  utilityUP, stateSize, discounting, error, numberOfTimeStampsLookAhead, numberOfSecondsCorrelation, 
						  trainDay, testDay, noCache);							  
				  
				  if (performExtraExperiments) {
						performEvaluation(cameraIds, clusters, Decision.lookaheadLocalProb, useAprioriProb, timeInFuture,utilityZoom,
								utilityUP,  stateSize, discounting, error, numberOfTimeStampsLookAhead, numberOfSecondsCorrelation, trainDay, testDay, noCache);
				    	performEvaluation(cameraIds, clusters, Decision.lookahead, useAprioriProb, timeInFuture, utilityZoom, 
				    			utilityUP, stateSize, discounting, error, numberOfTimeStampsLookAhead, 1, 
				    			trainDay, testDay, noCache);	
				  }
				  System.out.println("Done with "+utilityZoom+"_"+utilityUP);
			  
			  }
		  }
		}
		System.out.println("Done with all!");
	}
	
	public static ArrayList<String> getCameraIds(boolean largeNetwork) {
		ArrayList<String> cameraIds = new ArrayList<String>();
		if (largeNetwork) {
			//cameraIds.add("8");
			cameraIds.add("9");
			//cameraIds.add("10");
			//cameraIds.add("11");
			//cameraIds.add("12");
			//cameraIds.add("13");
			cameraIds.add("14");
			cameraIds.add("15");
			cameraIds.add("16");
			//cameraIds.add("17");
			//cameraIds.add("18");
	/*	
			cameraIds.add("cam19");
			cameraIds.add("cam20");
			cameraIds.add("cam21");
			cameraIds.add("cam22");
			cameraIds.add("cam23");
			cameraIds.add("cam24");
			cameraIds.add("cam25");
			cameraIds.add("cam26");
			cameraIds.add("cam27");
			cameraIds.add("cam28");
			cameraIds.add("cam29");
	*/		
			cameraIds.add("30");
			cameraIds.add("31");
			cameraIds.add("32");
			cameraIds.add("33");
			//cameraIds.add("cam34");
			cameraIds.add("35");
			//cameraIds.add("cam36");
			cameraIds.add("37");
			cameraIds.add("38");
			//cameraIds.add("cam39");
	//		//cameraIds.add("cam40");
	//		
	//		cameraIds.add("cam41");
	//		cameraIds.add("cam42");
	//		cameraIds.add("cam43");
	//		cameraIds.add("cam44");
	//		cameraIds.add("cam45");
	//		cameraIds.add("cam46");
	//		cameraIds.add("cam47");
	//		cameraIds.add("cam48");
	//		cameraIds.add("cam49");
	//		cameraIds.add("cam50");
	//		cameraIds.add("cam51");
		} else {
			if (ExperimentManager.isViewEnabled) {
				//cameraIds.add("11");
				//cameraIds.add("13");
				//cameraIds.add("14");
				//cameraIds.add("16");
				cameraIds.add("17");
				cameraIds.add("18");
			} 
			else if (ExperimentManager.useManualDataFormat) {
				cameraIds.add("11");
				cameraIds.add("13");
				cameraIds.add("14");
				cameraIds.add("16");
				cameraIds.add("17");
				cameraIds.add("18");				
			}
			else {
				cameraIds.add("13");
				cameraIds.add("14");
				cameraIds.add("15");
				cameraIds.add("16");
				cameraIds.add("17");
				cameraIds.add("18");
			}

		}
		return cameraIds;
	}
	public static void performEvaluation(ArrayList<String> cameraIds, int numClusters, Decision decision, 
			boolean useAprioriProb, int timeInFuture, double utilityZoom, double utilityUP, 
			int maxNumberOfStates, boolean discounting, double errorTolerance, int numberOfTimeStampsLookAhead,
			int numberOfSecondsCorrelation, String trainDay, String testDay, boolean noCache) throws NumberFormatException, Exception{
		String FILE_NAME_FORMAT = ExperimentManager.fileNameFormat;
		EndToEndTestUtils.evaluateSchedule(
				cameraIds, FILE_NAME_FORMAT, numClusters,
				numberOfTimeStampsLookAhead,
				numberOfSecondsCorrelation,
				maxNumberOfStates,
				utilityZoom,
				utilityUP,
				discounting,
				errorTolerance,
				noCache,
				decision, useAprioriProb, timeInFuture, trainDay, testDay);				
	}
	
	@Test public void testCountZoomoutEvents16_18() throws NumberFormatException, Exception{
		
		String testDay = "20090528";
		String trainDay = "20090527";
		boolean floor = true;
		boolean noCache = false;
		boolean useAprioriProb = false;
		int timeInFuture = 0;

		int numberOfTimeStampsLookAhead = 25;
		int numberOfSecondsCorrelation = 15;
		double delta = 1;
		int stateSize = 10000;

		
		double zoomu = 0.2; 
		double upu = 0;

		ArrayList<String> cameraIds = new ArrayList<String>();
		cameraIds.add("cam16");
		cameraIds.add("cam17");
		cameraIds.add("cam18");
		
		performEvaluation(cameraIds, 4, null, useAprioriProb, timeInFuture, zoomu, upu, stateSize, false, delta, numberOfTimeStampsLookAhead,
				numberOfSecondsCorrelation, testDay, trainDay, noCache);

		
	}
	
	@Test public void testCountZoomoutEvents13_18() throws NumberFormatException, Exception{
		boolean noCache = false;

		String testDay = "20090528";
		String trainDay = "20090527";
		boolean floor = true;
		
		boolean useAprioriProb = true;
		int timeInFuture = 0;
		double delta = 1;
		double zoomu = 0.2; 
		double upu = 0;
		int stateSize = 10000;

		ArrayList<String> cameraIds = new ArrayList<String>();
		cameraIds.add("cam13");
		cameraIds.add("cam14");
		cameraIds.add("cam15");
		cameraIds.add("cam16");
		cameraIds.add("cam17");
		cameraIds.add("cam18");

		//performEvauation(cameraIds, Decision.up, zoomu, upu, delta, 25);
		performEvaluation(cameraIds, 4, Decision.lookahead, zoomu, upu, stateSize, false,
				useAprioriProb, timeInFuture, delta, 25, 15, testDay, trainDay, noCache);
		//performEvauation(cameraIds, Decision.lookahead, zoomu, upu, delta, 1);


		
	}
}
